import cv2
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt
from xml.dom.minidom import parse
import pytesseract
import os


def shice_record(All_cell_points, Rows):
    """
    :param All_cell_points: 解析单元格得到的表格的结构信息
    :param Rows: 表格的 Rows 信息
    :return: record : 包含待检测的“实测”项的单元格位置信息， 行列信息，合并单元格数量
    """
    record = []

    for index_row in range(len(Rows)):

        # 获取每一行中的单元格并计算
        cells = Rows[index_row].getElementsByTagName('Cell')

        for index_cell, cell in enumerate(cells):

            data = cell.getElementsByTagName('Data')

            if (len(data)):

                value = data[0].childNodes[0].data
                if "实测" in value:
                    print('yes')
                    print(value)

                    if cell.getAttribute("ss:MergeDown") == '':
                        num_row_measure = 1

                    else:
                        num_row_measure = int(cell.getAttribute("ss:MergeDown"))

                    record.append([All_cell_points[index_row][index_cell], [index_row, index_cell, num_row_measure]])

    return record


def takeElementUpLine(l):
    return l[0][0][0]


def shice_class(record):
    """
    该函数作用：将“实测”分类，同一组拥有同一个’标准‘
    :param record: 初步赛选出的“实测”
    :return: 分类后的“实测”单元格相关的信息
    """
    # 将“实测”分类
    # 上下挨着的“实测”即为同一“标准”下的待检测实测值；不挨着的即不同的标准值；
    # “挨着”衡量标准：待分类的单元格的左上角点和右上角点的位置与上一个单元格的左下角点和右下角点的位置相同。

    tow_points_list = []  # 对应存放着“实测”单元格的左下角点和右下角点的坐标值,以及每个单元格对应的类别
    for shice_record in record:
        shice_cell_point = shice_record[0]
        # 计算待分类单元格的上面四个角点坐标值
        shice_point_lu = shice_cell_point[0]
        shice_point_ru = [shice_cell_point[0][0], shice_cell_point[1][1]]
        shice_point_ld = [shice_cell_point[1][0], shice_cell_point[0][1]]
        shice_point_rd = shice_cell_point[1]
        tow_points_list.append([shice_point_lu, shice_point_ru, shice_point_ld, shice_point_rd, shice_record, 0])

    class_index = 0
    for index_item, item_shice in enumerate(tow_points_list):
        class_flag = item_shice[-1]
        if class_flag != 0:  # 该“实测”已有分类，直接跳过
            break
        class_index = class_index + 1
        tow_points_list[index_item][-1] = class_index
        for index_x, x in enumerate(tow_points_list):
            if index_item == index_x:
                continue
            points_x = x[0:4]
            sum_index = 0
            for p in item_shice[:4]:
                if (p in points_x):
                    sum_index = sum_index + points_x.index(p)
            if sum_index % 2:  # 单元格上顶线坐标索引是0 1  下底线坐标索引是2 3
                tow_points_list[index_x][-1] = tow_points_list[index_item][-1]

    # 存放拥有相同标准值的待检测实测值
    shice_list = []
    for i in range(class_index):
        l = []
        for cell_inform in tow_points_list:
            if cell_inform[-1] == i + 1:
                l.append(cell_inform[-2])
        shice_list.append(l)
    return shice_list


def shice_testAgain(Rows, shice_list, All_cell_low):
    """
    该函数的作用：对‘实测’进一步筛选，筛选标准：检测检测之上是否有“标准”
    :param Rows: 表格Rows信息
    :param shice_list: 相同‘标准’的“实测”集合
    :param All_cell_low: 以单元格底线为标准排序的单元格位置信息集合
    :return: record_biaozhun：筛选后对应的‘标准’  record_saixuan：筛选后的”实测“
    """
    # 对筛选出来的“实测”进一步判断
    record_biaozhun = []

    shice_record_saixuan = []

    for shice_same_list in shice_list:
        # 根据单元格顶线对“实测”进行排序，使shice_same_list第一个“实测”为和“标准”相接的“实测”，
        # 便于进行再检测以及找到这一组“实测”对应的“标准”
        shice_same_list.sort(key=takeElementUpLine())
        shice_record = shice_same_list[0]
        shice_cell_points = shice_record[0]
        # print(shice_cell_points)
        # 计算出上面相邻的单元格右角点的坐标值
        shice_pre_rl = [shice_cell_points[0][0], shice_cell_points[1][1]]

        # 遍历一遍所有的单元格找出“实测”上面一个单元格
        for i in range(len(All_cell_low)):

            for cell in All_cell_low[i]:
                # 找出单元格与该右角点值相等的单元格
                if shice_pre_rl in cell[0] and cell[0].index(shice_pre_rl) == 1:

                    cell_jiance = Rows[cell[1][0]].getElementsByTagName('Cell')[cell[1][1]]
                    data = cell_jiance.getElementsByTagName('Data')
                    value = data[0].childNodes[0].data

                    if "标准" in value or "Sample":
                        shice_record_saixuan.append(shice_same_list)
                        record_biaozhun.append(cell)

    return record_biaozhun, shice_record_saixuan


def num_shice(shice_record_saixuan, All_cell_low, biaozhun_list, Rows):
    """

    :param shice_record_saixuan: ’实测‘单元格的信息
    :param All_cell_low: 以row col 两个方向均进行排序过的每个单元格的位置信息
    :param biaozhun_list: 标准值的相关信息
    :param Rows: 表格的行信息
    :return: shice_index 返回待测实测值的相关信息  shice_index[不同标准值的实测组[相同标准值的实测值集合]]
    """
    records = shice_record_saixuan
    # 存放前一个单元格的右下角点以及“实测”单元格的高度
    point_height = 0
    # 存放 “实测”的单元格索引
    shice_index = []

    for index_record, record_list in enumerate(records):

        # biaozhun_num = len(biaozhun_index[index_record])

        # 获得每个标准值的横线列表
        biaozhun_hengxian_list = [x[1] for x in biaozhun_list[index_record]]

        # record_list : 拥有相同标准值的“实测”

        # 找出所有在“实测单元格”范围之内的所有的单元格，即单元格的底线在单元格顶线、底线在“实测”顶线、底线之内
        # 对同一“标准值”的实测值进行筛选

        # 上顶线
        up_shice = record_list[0][0][0][0]
        # 下底线
        low_shice = record_list[-1][0][1][0]

        index_low = []
        for i, low_points in enumerate(All_cell_low):

            # 判断这一行中是否有输入“实测”的实测值
            for low_point in low_points:
                # 待测单元格的底线小于等于“实测”的底线 且待测单元格的顶线大于等于“实测”的顶线
                if low_point[0][1][0] <= low_shice and low_point[0][0][0] >= up_shice:
                    index_low.append(i)  # i： 拥有对应实测值的行数索引

        index_low = list(set(index_low))  # 去重

        shice_l = []
        for record in record_list:

            # 同一“标准”下的“实测”的高度
            point_height = record_list[-1][0][1][0] - record_list[0][0][0][0]

            # 一个“实测”下的底线值和顶线值
            point_low_line = record[0][1][0]
            point_up_line = record[0][0][0]

            # 将符合“实测”的单元格聚集
            cells = []
            for index in index_low:
                cell = All_cell_low[index]
                cells = cells + cell
                # cells = All_cell_low[index_low[index]]

            shice_cell_information = []
            # print(cell)
            for cell in cells:
                flag_hengxian = 0
                # print(cell)
                # 计算待测单元格的顶线、底线高度以及其单元格高度
                cell_up_line = cell[0][0][0]
                cell_low_line = cell[0][1][0]
                cell_height = cell[0][1][0] - cell[0][0][0]

                # print("cell_height:", cell_height)
                cell_jiance = Rows[cell[1][0]].getElementsByTagName('Cell')[cell[1][1]]
                data = cell_jiance.getElementsByTagName('Data')
                value = data[0].childNodes[0].data
                # print("cell:",cell)
                # print(value, cell[1])

                # 单元格横线的坐标， 通过单元格横线起始和终点col值来检验实测值是否和标准值对应
                point_hengxian = [cell[0][0][1], cell[0][1][1]]
                # # 实测值对应着标准值的索引
                biaozhun_index_list = 0
                if point_hengxian in biaozhun_hengxian_list:
                    flag_hengxian = 1
                    # 实测值对应着标准值的索引
                    biaozhun_index_list = biaozhun_hengxian_list.index(point_hengxian)

                if flag_hengxian and cell_height <= point_height and point_low_line >= cell_low_line > point_up_line:
                    # print(value)
                    #                     print("point_low_line:",point_low_line, "point_up_line", point_up_line)
                    #                     print(cell_low_line)
                    l = [cell[1], cell[0][2], biaozhun_index_list]
                    shice_cell_information.append(l)

                # print(value)
            # 拥有相同标准值的实测值的信息
            shice_l.append(shice_cell_information)
        # 所有的实测值的信息
        shice_index.append(shice_l)

    return shice_index
